package com.example.model.utils;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTException;
import cn.hutool.jwt.Claims;
import com.example.model.pojo.User;
import org.springframework.boot.autoconfigure.AutoConfiguration;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类，用于生成、解析和验证JWT令牌
 * 使用Hutool工具包实现JWT相关功能
 */
@AutoConfiguration
public class JwtUtils {

    /**
     * JWT签名密钥
     * 实际生产环境中应使用更安全的密钥，并通过配置文件或环境变量管理
     */
    private static final String SECRET_KEY = "software_course_design_secret_key_2024";
    
    /**
     * JWT过期时间（7天）
     * 可根据实际需求调整过期时间
     */
    private static final long EXPIRATION_TIME = 7 * 24 * 60 * 60 * 1000;
    
    /**
     * 令牌前缀，用于从请求头中提取令牌
     */
    public static final String TOKEN_PREFIX = "Bearer ";

    /**
     * 生成JWT令牌
     * @param user 用户信息对象
     * @return 生成的JWT令牌字符串
     * @throws IllegalArgumentException 当用户信息为空时抛出异常
     */
    public String generateToken(User user) {
        if (user == null) {
            throw new IllegalArgumentException("用户信息不能为空");
        }
        
        // 创建JWT载荷信息
        Map<String, Object> payload = new HashMap<>();
        payload.put("userId", user.getId());
        payload.put("name", user.getName());
        payload.put("role", user.getRole());
        payload.put("studentId", user.getStudentId());
        payload.put("teacherId", user.getTeacherId());
        payload.put("iat", new Date()); // 签发时间
        payload.put("exp", new Date(System.currentTimeMillis() + EXPIRATION_TIME)); // 过期时间
        
        try {
            // 使用Hutool的JWTUtil生成JWT令牌，使用HS256算法签名
            return JWTUtil.createToken(payload, SECRET_KEY.getBytes());
        } catch (Exception e) {
            throw new RuntimeException("生成JWT令牌失败: " + e.getMessage(), e);
        }
    }

    /**
     * 解析JWT令牌
     * @param token JWT令牌字符串
     * @return JWT解析后的Claims对象
     * @throws JWTException 当令牌格式错误或解析失败时抛出异常
     */
    public Claims parseToken(String token) throws JWTException {
        if (token == null || token.trim().isEmpty()) {
            throw new JWTException("令牌不能为空");
        }
        
        try {
            // 解析令牌
            JWT jwt = JWTUtil.parseToken(token);
            // 验证签名
            if (!jwt.setKey(SECRET_KEY.getBytes()).verify()) {
                throw new JWTException("无效的JWT令牌: 签名验证失败");
            }
            // 验证是否过期
            if (!jwt.validate(0)) {
                throw new JWTException("JWT令牌已过期");
            }
            
            return jwt.getPayload();
        } catch (JWTException e) {
            throw e; // 直接抛出JWT相关异常
        } catch (Exception e) {
            throw new JWTException("解析JWT令牌失败: " + e.getMessage(), e);
        }
    }

    /**
     * 验证令牌是否有效
     * @param token JWT令牌字符串
     * @return 令牌是否有效
     */
    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (Exception e) {
            // 捕获所有异常，返回false表示令牌无效
            return false;
        }
    }

    /**
     * 从令牌中获取用户ID
     * @param token JWT令牌字符串
     * @return 用户ID
     * @throws JWTException 当令牌无效或无法获取用户ID时抛出异常
     */
    public Integer getUserIdFromToken(String token) throws JWTException {
        Claims claims = parseToken(token);
        try {
            return claims.getClaimsJson().getInt("userId");
        } catch (Exception e) {
            throw new JWTException("无法从令牌中获取用户ID", e);
        }
    }

    /**
     * 从令牌中获取用户角色
     * @param token JWT令牌字符串
     * @return 用户角色
     * @throws JWTException 当令牌无效或无法获取用户角色时抛出异常
     */
    public Integer getUserRoleFromToken(String token) throws JWTException {
        Claims claims = parseToken(token);
        try {
            return claims.getClaimsJson().getInt("role");
        } catch (Exception e) {
            throw new JWTException("无法从令牌中获取用户角色", e);
        }
    }

    /**
     * 从请求头中提取令牌
     * @param authorizationHeader Authorization请求头
     * @return 提取的令牌字符串（不含Bearer前缀）
     * @throws IllegalArgumentException 当请求头格式不正确时抛出异常
     */
    public String extractTokenFromHeader(String authorizationHeader) {
        if (authorizationHeader == null || !authorizationHeader.startsWith(TOKEN_PREFIX)) {
            throw new IllegalArgumentException("无效的Authorization请求头格式");
        }
        return authorizationHeader.substring(TOKEN_PREFIX.length());
    }

    /**
     * 从令牌中获取用户名
     * @param token JWT令牌字符串
     * @return 用户名
     * @throws JWTException 当令牌无效或无法获取用户信息时抛出异常
     */
    public String getUserNameFromToken(String token) throws JWTException {
        Claims claims = parseToken(token);
        try {
            return claims.getClaimsJson().getStr("name");
        } catch (Exception e) {
            throw new JWTException("无法从令牌中获取用户名", e);
        }
    }
}